home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 022 / lemacs / bind.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  19KB  |  809 lines

  1. /*    This file is for functions having to do with key bindings,
  2.     descriptions, help commands, and command line execution.
  3.  
  4.     written 11-feb-86 by Daniel Lawrence
  5.                                 */
  6.  
  7. #include    <stdio.h>
  8. #include    "estruct.h"
  9. #include    "edef.h"
  10. #include    "epath.h"
  11.  
  12. deskey(f, n)    /* describe the command for a certain key */
  13. {
  14.     register int c;        /* command character to describe */
  15.     register char *ptr;    /* string pointer to scan output strings */
  16.     register KEYTAB *ktp;    /* pointer into the command table */
  17.     register int found;    /* matched command flag */
  18.     register NBIND *nptr;    /* pointer into the name binding table */
  19.     char outseq[80];    /* output buffer for command sequence */
  20.  
  21.     /* prompt the user to type us a key to describe */
  22.     mlwrite(": describe-key ");
  23.  
  24.     /* get the command sequence to describe */
  25.     c = getckey();            /* get a command sequence */
  26.  
  27.     /* change it to something we can print as well */
  28.     cmdstr(c, &outseq[0]);
  29.  
  30.     /* and dump it out */
  31.     ptr = &outseq[0];
  32.     while (*ptr)
  33.         (*term.t_putchar)(*ptr++);
  34.     (*term.t_putchar)(' ');        /* space it out */
  35.  
  36.     /* find the right ->function */
  37.     ktp = &keytab[0];
  38.     found = FALSE;
  39.     while (ktp->k_fp != NULL) {
  40.         if (ktp->k_code == c) {
  41.             found = TRUE;
  42.             break;
  43.         }
  44.         ++ktp;
  45.     }
  46.  
  47.     if (!found)
  48.         strcpy(outseq,"Not Bound");
  49.     else {
  50.         /* match it against the name binding table */
  51.         nptr = &names[0];
  52.         strcpy(outseq,"[Bad binding]");
  53.         while (nptr->n_func != NULL) {
  54.             if (nptr->n_func == ktp->k_fp) {
  55.                 strcpy(outseq, nptr->n_name);
  56.                 break;
  57.             }
  58.             ++nptr;
  59.         }
  60.     }
  61.  
  62.     /* output the command sequence */
  63.     ptr = &outseq[0];
  64.     while (*ptr)
  65.         (*term.t_putchar)(*ptr++);
  66. }
  67.  
  68. cmdstr(c, seq)    /* change a key command to a string we can print out */
  69.  
  70. int c;        /* sequence to translate */
  71. char *seq;    /* destination string for sequence */
  72.  
  73. {
  74.     char *ptr;    /* pointer into current position in sequence */
  75.  
  76.     ptr = seq;
  77.  
  78.     /* apply meta sequence if needed */
  79.     if (c & META) {
  80.         *ptr++ = 'M';
  81.         *ptr++ = '-';
  82.     }
  83.  
  84.     /* apply ^X sequence if needed */
  85.     if (c & CTLX) {
  86.         *ptr++ = '^';
  87.         *ptr++ = 'X';
  88.     }
  89.  
  90.     /* apply SPEC sequence if needed */
  91.     if (c & SPEC) {
  92.         *ptr++ = 'F';
  93.         *ptr++ = 'N';
  94.     }
  95.  
  96.     /* apply control sequence if needed */
  97.     if (c & CTRL) {
  98.         *ptr++ = '^';
  99.     }
  100.  
  101.     c = c & 255;    /* strip the prefixes */
  102.  
  103.     /* and output the final sequence */
  104.  
  105.     *ptr++ = c;
  106.     *ptr = 0;    /* terminate the string */
  107. }
  108.  
  109. help(f, n)    /* give me some help!!!!
  110.            bring up a fake buffer and read the help file
  111.            into it with view mode            */
  112. {
  113.     register int status;    /* status of I/O operations */
  114.     register WINDOW *wp;    /* scnaning pointer to windows */
  115.     register int i;        /* index into help file names */
  116.     char fname[NSTRING];    /* buffer to construct file name in */
  117.  
  118.     /* search through the list of help files */
  119.     for (i=2; i < NPNAMES; i++) {
  120.         strcpy(fname, pathname[i]);
  121.         strcat(fname, pathname[1]);
  122.         status = ffropen(fname);
  123.         if (status == FIOSUC)
  124.             break;
  125.     }
  126.  
  127.     if (status == FIOFNF) {
  128.         mlwrite("[Help file is not online]");
  129.         return(FALSE);
  130.     }
  131.     ffclose();    /* close the file to prepare for to read it in */
  132.  
  133.     /* split the current window to make room for the help stuff */
  134.     if (splitwind(FALSE, 1) == FALSE)
  135.             return(FALSE);
  136.  
  137.     /* and read the stuff in */
  138.     if (getfile(fname, FALSE) == FALSE)
  139.         return(FALSE);
  140.  
  141.     /* make this window in VIEW mode, update all mode lines */
  142.     curwp->w_bufp->b_mode |= MDVIEW;
  143.     wp = wheadp;
  144.     while (wp != NULL) {
  145.         wp->w_flag |= WFMODE;
  146.         wp = wp->w_wndp;
  147.     }
  148.     return(TRUE);
  149. }
  150.  
  151. int (*fncmatch(fname))() /* match fname to a function in the names table
  152.                 and return any match or NULL if none        */
  153.  
  154. char *fname;    /* name to attempt to match */
  155.  
  156. {
  157.     register NBIND *ffp;    /* pointer to entry in name binding table */
  158.  
  159.     /* scan through the table, returning any match */
  160.     ffp = &names[0];
  161.     while (ffp->n_func != NULL) {
  162.         if (strcmp(fname, ffp->n_name) == 0)
  163.             return(ffp->n_func);
  164.         ++ffp;
  165.     }
  166.     return(NULL);
  167. }
  168.  
  169. /* bindtokey:    add a new key to the key binding table
  170. */
  171.  
  172. bindtokey(f, n)
  173.  
  174. int f, n;    /* command arguments [IGNORED] */
  175.  
  176. {
  177.     register int c;        /* command key to bind */
  178.     register (*kfunc)();    /* ptr to the requexted function to bind to */
  179.     register char *ptr;    /* ptr to dump out input key string */
  180.     register KEYTAB *ktp;    /* pointer into the command table */
  181.     register int found;    /* matched command flag */
  182.     char outseq[80];    /* output buffer for keystroke sequence */
  183.     int (*getname())();
  184.  
  185.     /* prompt the user to type in a key to bind */
  186.     mlwrite(": bind-to-key ");
  187.  
  188.     /* get the function name to bind it to */
  189.     kfunc = getname();
  190.     if (kfunc == NULL) {
  191.         mlwrite("[No such function]");
  192.         return(FALSE);
  193.     }
  194.     (*term.t_putchar)(' ');        /* space it out */
  195.     (*term.t_flush)();
  196.  
  197.     /* get the command sequence to bind */
  198.     c = getckey();            /* get a command sequence */
  199.  
  200.     /* change it to something we can print as well */
  201.     cmdstr(c, &outseq[0]);
  202.  
  203.     /* and dump it out */
  204.     ptr = &outseq[0];
  205.     while (*ptr)
  206.         (*term.t_putchar)(*ptr++);
  207.  
  208.     /* search the table to see if it exists */
  209.     ktp = &keytab[0];
  210.     found = FALSE;
  211.     while (ktp->k_fp != NULL) {
  212.         if (ktp->k_code == c) {
  213.             found = TRUE;
  214.             break;
  215.         }
  216.         ++ktp;
  217.     }
  218.  
  219.     if (found) {    /* it exists, just change it then */
  220.         ktp->k_fp = kfunc;
  221.     } else {    /* otherwise we need to add it to the end */
  222.         /* if we run out of binding room, bitch */
  223.         if (ktp >= &keytab[NBINDS]) {
  224.             mlwrite("Binding table FULL!");
  225.             return(FALSE);
  226.         }
  227.  
  228.         ktp->k_code = c;    /* add keycode */
  229.         ktp->k_fp = kfunc;    /* and the function pointer */
  230.         ++ktp;            /* and make sure the next is null */
  231.         ktp->k_code = 0;
  232.         ktp->k_fp = NULL;
  233.     }
  234.  
  235.     return(TRUE);
  236. }
  237.  
  238. /* unbindkey:    delete a key from the key binding table
  239. */
  240.  
  241. unbindkey(f, n)
  242.  
  243. int f, n;    /* command arguments [IGNORED] */
  244.  
  245. {
  246.     register int c;        /* command key to unbind */
  247.     register char *ptr;    /* ptr to dump out input key string */
  248.     register KEYTAB *ktp;    /* pointer into the command table */
  249.     register KEYTAB *sktp;    /* saved pointer into the command table */
  250.     register int found;    /* matched command flag */
  251.     char outseq[80];    /* output buffer for keystroke sequence */
  252.  
  253.     /* prompt the user to type in a key to unbind */
  254.     mlwrite(": unbind-key ");
  255.  
  256.     /* get the command sequence to unbind */
  257.     c = getckey();            /* get a command sequence */
  258.  
  259.     /* change it to something we can print as well */
  260.     cmdstr(c, &outseq[0]);
  261.  
  262.     /* and dump it out */
  263.     ptr = &outseq[0];
  264.     while (*ptr)
  265.         (*term.t_putchar)(*ptr++);
  266.  
  267.     /* search the table to see if the key exists */
  268.     ktp = &keytab[0];
  269.     found = FALSE;
  270.     while (ktp->k_fp != NULL) {
  271.         if (ktp->k_code == c) {
  272.             found = TRUE;
  273.             break;
  274.         }
  275.         ++ktp;
  276.     }
  277.  
  278.     /* if it isn't bound, bitch */
  279.     if (!found) {
  280.         mlwrite("[Key not bound]");
  281.         return(FALSE);
  282.     }
  283.  
  284.     /* save the pointer and scan to the end of the table */
  285.     sktp = ktp;
  286.     while (ktp->k_fp != NULL)
  287.         ++ktp;
  288.     --ktp;        /* backup to the last legit entry */
  289.  
  290.     /* copy the last entry to the current one */
  291.     sktp->k_code = ktp->k_code;
  292.     sktp->k_fp   = ktp->k_fp;
  293.  
  294.     /* null out the last one */
  295.     ktp->k_code = 0;
  296.     ktp->k_fp = NULL;
  297.     return(TRUE);
  298. }
  299.  
  300. /* namedcmd:    execute a named command even if it is not bound
  301. */
  302.  
  303. namedcmd(f, n)
  304.  
  305. int f, n;    /* command arguments [passed through to command executed] */
  306.  
  307. {
  308.     register (*kfunc)();    /* ptr to the requexted function to bind to */
  309.     int (*getname())();
  310.  
  311.     /* prompt the user to type a named command */
  312.     mlwrite(": ");
  313.  
  314.     /* and now get the function name to execute */
  315.     kfunc = getname();
  316.     if (kfunc == NULL) {
  317.         mlwrite("[No such function]");
  318.         return(FALSE);
  319.     }
  320.  
  321.     /* and then execute the command */
  322.     return((*kfunc)(f, n));
  323. }
  324.  
  325. desbind(f, n)    /* describe bindings
  326.            bring up a fake buffer and list the key bindings
  327.            into it with view mode            */
  328. {
  329.     register WINDOW *wp;    /* scnaning pointer to windows */
  330.     register KEYTAB *ktp;    /* pointer into the command table */
  331.     register NBIND *nptr;    /* pointer into the name binding table */
  332.     register BUFFER *bp;    /* buffer to put binding list into */
  333.     char *strp;        /* pointer int string to send */
  334.     int cpos;        /* current position to use in outseq */
  335.     char outseq[80];    /* output buffer for keystroke sequence */
  336.  
  337.     /* split the current window to make room for the binding list */
  338.     if (splitwind(FALSE, 1) == FALSE)
  339.             return(FALSE);
  340.  
  341.     /* and get a buffer for it */
  342.     bp = bfind("Binding list", TRUE, 0);
  343.     if (bp == NULL || bclear(bp) == FALSE) {
  344.         mlwrite("Can not display binding list");
  345.         return(FALSE);
  346.     }
  347.  
  348.     /* let us know this is in progress */
  349.     mlwrite("[Building buffer list]");
  350.  
  351.     /* disconect the current buffer */
  352.         if (--curbp->b_nwnd == 0) {             /* Last use.            */
  353.                 curbp->b_dotp  = curwp->w_dotp;
  354.                 curbp->b_doto  = curwp->w_doto;
  355.                 curbp->b_markp = curwp->w_markp;
  356.                 curbp->b_marko = curwp->w_marko;
  357.         }
  358.  
  359.     /* connect the current window to this buffer */
  360.     curbp = bp;    /* make this buffer current in current window */
  361.     bp->b_mode = 0;        /* no modes active in binding list */
  362.     bp->b_nwnd++;        /* mark us as more in use */
  363.     wp = curwp;
  364.     wp->w_bufp = bp;
  365.     wp->w_linep = bp->b_linep;
  366.     wp->w_flag = WFHARD|WFFORCE|WFHARD;
  367.     wp->w_dotp = bp->b_dotp;
  368.     wp->w_doto = bp->b_doto;
  369.     wp->w_markp = NULL;
  370.     wp->w_marko = 0;
  371.  
  372.     /* build the contents of this window, inserting it line by line */
  373.     nptr = &names[0];
  374.     while (nptr->n_func != NULL) {
  375.  
  376.         /* add in the command name */
  377.         strcpy(outseq, nptr->n_name);
  378.         cpos = strlen(outseq);
  379.         
  380.         /* search down any keys bound to this */
  381.         ktp = &keytab[0];
  382.         while (ktp->k_fp != NULL) {
  383.             if (ktp->k_fp == nptr->n_func) {
  384.                 /* padd out some spaces */
  385.                 while (cpos < 25)
  386.                     outseq[cpos++] = ' ';
  387.  
  388.                 /* add in the command sequence */
  389.                 cmdstr(ktp->k_code, &outseq[cpos]);
  390.                 while (outseq[cpos] != 0)
  391.                     ++cpos;
  392.  
  393.                 /* and add it as a line into the buffer */
  394.                 strp = &outseq[0];
  395.                 while (*strp != 0)
  396.                     linsert(1, *strp++);
  397.                 lnewline();
  398.  
  399.                 cpos = 0;    /* and clear the line */
  400.             }
  401.             ++ktp;
  402.         }
  403.  
  404.         /* if no key was bound, we need to dump it anyway */
  405.         if (cpos > 0) {
  406.             outseq[cpos] = 0;
  407.             strp = &outseq[0];
  408.             while (*strp != 0)
  409.                 linsert(1, *strp++);
  410.             lnewline();
  411.         }
  412.  
  413.         /* and on to the next name */
  414.         ++nptr;
  415.     }
  416.  
  417.     curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
  418.     curbp->b_flag &= ~BFCHG;    /* don't flag this as a change */
  419.     wp->w_dotp = lforw(bp->b_linep);/* back to the begining */
  420.     wp->w_doto = 0;
  421.     wp = wheadp;            /* and update ALL mode lines */
  422.     while (wp != NULL) {
  423.         wp->w_flag |= WFMODE;
  424.         wp = wp->w_wndp;
  425.     }
  426.     mlwrite("");    /* clear the mode line */
  427.     return(TRUE);
  428. }
  429.  
  430. /*    execcmd:    Execute a command line command to be typed in
  431.             by the user                    */
  432.  
  433. execcmd(f, n)
  434.  
  435. int f, n;    /* default Flag and Numeric argument */
  436.  
  437. {
  438.     register int status;        /* status return */
  439.     char cmdstr[NSTRING];        /* string holding command to execute */
  440.  
  441.     /* get the line wanted */
  442.     if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  443.         return(status);
  444.  
  445.     return(docmd(cmdstr));
  446. }
  447.  
  448. /*    docmd:    take a passed string as a command line and translate
  449.         it to be executed as a command. This function will be
  450.         used by execute-command-line and by all source and
  451.         startup files.
  452.  
  453.     format of the command line is:
  454.  
  455.         {# arg} <command-name> {<argument string(s)>}
  456. */
  457.  
  458. docmd(cline)
  459.  
  460. char *cline;    /* command line to execute */
  461.  
  462. {
  463.     register char *cp;    /* pointer to current position in command */
  464.     register char *tp;    /* pointer to current position in token */
  465.     register int f;        /* default argument flag */
  466.     register int n;        /* numeric repeat value */
  467.     register int sign;    /* sign of numeric argument */
  468.     register int (*fnc)();    /* function to execute */
  469.     register int status;    /* return status of function */
  470.     register int oldcle;    /* old contents of clexec flag */
  471.     char token[NSTRING];    /* next token off of command line */
  472.     int (*fncmatch())();
  473.     char *gettok();
  474.  
  475.     /* first set up the default command values */
  476.     f = FALSE;
  477.     n = 1;
  478.  
  479.     cp = cline;        /* start at the begining of the line */
  480.     cp = gettok(cp, token);    /* and grab the first token */
  481.  
  482.     /* check for and process numeric leadin argument */
  483.     if ((token[0] >= '0' && token[0] <= '9') || token[0] == '-') {
  484.         f = TRUE;
  485.         n = 0;
  486.         tp = &token[0];
  487.  
  488.         /* check for a sign! */
  489.         sign = 1;
  490.         if (*tp == '-') {
  491.             ++tp;
  492.             sign = -1;
  493.         }
  494.  
  495.         /* calc up the digits in the token string */
  496.         while(*tp) {
  497.             if (*tp >= '0' && *tp <= '9')
  498.                 n = n * 10 + *tp - '0';
  499.             ++tp;
  500.         }
  501.         n *= sign;    /* adjust for the sign */
  502.  
  503.         /* and now get the command to execute */
  504.         cp = gettok(cp, token);        /* grab the next token */
  505.     }
  506.  
  507.     /* and match the token to see if it exists */
  508.     if ((fnc = fncmatch(token)) == NULL) {
  509.         mlwrite("[No such Function]");
  510.         return(FALSE);
  511.     }
  512.     
  513.     /* save the arguments and go execute the command */
  514.     strcpy(sarg, cp);        /* save the rest */
  515.     oldcle = clexec;        /* save old clexec flag */
  516.     clexec = TRUE;            /* in cline execution */
  517.     status = (*fnc)(f, n);        /* call the function */
  518.     clexec = oldcle;        /* restore clexec flag */
  519.     return(status);
  520. }
  521.  
  522. /* gettok:    chop a token off a string
  523.         return a pointer past the token
  524. */
  525.  
  526. char *gettok(src, tok)
  527.  
  528. char *src, *tok;    /* source string, destination token */
  529.  
  530. {
  531.     /* first scan past any whitespace in the source string */
  532.     while (*src == ' ' || *src == '\t')
  533.         ++src;
  534.  
  535.     /* if quoted, go till next quote */
  536.     if (*src == '"') {
  537.         ++src;        /* past the quote */
  538.         while (*src != 0 && *src != '"')
  539.             *tok++ = *src++;
  540.         ++src;        /* past the last quote */
  541.         *tok = 0;    /* terminate token and return */
  542.         return(src);
  543.     }
  544.  
  545.     /* copy until we find the end or whitespace */
  546.     while (*src != 0 && *src != ' ' && *src != '\t')
  547.         *tok++ = *src++;
  548.  
  549.     /* terminate tok and return */
  550.     *tok = 0;
  551.     return(src);
  552. }
  553.  
  554. /* nxtarg:    grab the next token out of sarg, return it, and
  555.         chop it of sarg                    */
  556.  
  557. nxtarg(tok)
  558.  
  559. char *tok;    /* buffer to put token into */
  560.  
  561. {
  562.     char *newsarg;    /* pointer to new begining of sarg */
  563.     char *gettok();
  564.  
  565.     newsarg = gettok(sarg, tok);    /* grab the token */
  566.     strcpy(sarg, newsarg);        /* and chop it of sarg */
  567.     return(TRUE);
  568. }
  569.  
  570. getckey()    /* get a command key sequence from the keyboard    */
  571.  
  572. {
  573.     register int c;        /* character fetched */
  574.     register char *tp;    /* pointer into the token */
  575.     char tok[NSTRING];    /* command incoming */
  576.  
  577.     /* check to see if we are executing a command line */
  578.     if (clexec) {
  579.         nxtarg(tok);    /* get the next token */
  580.  
  581.         /* parse it up */
  582.         tp = &tok[0];
  583.         c = 0;
  584.  
  585.         /* first, the META prefix */
  586.         if (*tp == 'M' && *(tp+1) == '-') {
  587.             c = META;
  588.             tp += 2;
  589.         }
  590.  
  591.         /* next the function prefix */
  592.         if (*tp == 'F' && *(tp+1) == 'N') {
  593.             c |= SPEC;
  594.             tp += 2;
  595.         }
  596.  
  597.         /* control-x as well... */
  598.         if (*tp == '^' && *(tp+1) == 'X') {
  599.             c |= CTLX;
  600.             tp += 2;
  601.         }
  602.  
  603.         /* a control char? */
  604.         if (*tp == '^' & *(tp+1) != 0) {
  605.             c |= CTRL;
  606.             ++tp;
  607.         }
  608.  
  609.         /* make sure we are not lower case */
  610.         if (c >= 'a' && c <= 'z')
  611.             c -= 32;
  612.  
  613.         /* the final sequence... */
  614.         c |= *tp;
  615.  
  616.         return(c);
  617.     }
  618.  
  619.     /* or the normal way */
  620.     c = getkey();            /* get a command sequence */
  621.     if (c == (CTRL|'X'))        /* get control-x sequence */
  622.         c = CTLX | getctl();
  623.     return(c);
  624. }
  625.  
  626. /*    execbuf:    Execute the contents of a named buffer    */
  627.  
  628. execbuf(f, n)
  629.  
  630. int f, n;    /* default flag and numeric arg */
  631.  
  632. {
  633.         register BUFFER *bp;        /* ptr to buffer to execute */
  634.         register int status;        /* status return */
  635.         char bufn[NBUFN];        /* name of buffer to execute */
  636.  
  637.     /* find out what buffer the user wants to execute */
  638.         if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
  639.                 return(status);
  640.  
  641.     /* find the pointer to that buffer */
  642.         if ((bp=bfind(bufn, TRUE, 0)) == NULL)
  643.                 return(FALSE);
  644.  
  645.     /* and now execute it as asked */
  646.     while (n-- > 0)
  647.         if ((status = dobuf(bp)) != TRUE)
  648.             return(status);
  649.     return(TRUE);
  650. }
  651.  
  652. /*    dobuf:    execute the contents of the buffer pointed to
  653.         by the passed BP                */
  654.  
  655. dobuf(bp)
  656.  
  657. BUFFER *bp;    /* buffer to execute */
  658.  
  659. {
  660.         register int status;        /* status return */
  661.     register LINE *lp;        /* pointer to line to execute */
  662.     register LINE *hlp;        /* pointer to line header */
  663.     register int linlen;        /* length of line to execute */
  664.     register WINDOW *wp;        /* ptr to windows to scan */
  665.     char eline[NSTRING];        /* text of line to execute */
  666.  
  667.     /* starting at the beginning of the buffer */
  668.     hlp = bp->b_linep;
  669.     lp = hlp->l_fp;
  670.     while (lp != hlp) {
  671.         /* calculate the line length and make a local copy */
  672.         linlen = lp->l_used;
  673.         if (linlen > NSTRING - 1)
  674.             linlen = NSTRING - 1;
  675.         strncpy(eline, lp->l_text, linlen);
  676.         eline[linlen] = 0;    /* make sure it ends */
  677.  
  678.         /* if it is not a comment, execute it */
  679.         if (eline[0] != ';' && eline[0] != 0) {
  680.             status = docmd(eline);
  681.             if (status != TRUE) {    /* a command error */
  682.                 /* look if buffer is showing */
  683.                 wp = wheadp;
  684.                 while (wp != NULL) {
  685.                     if (wp->w_bufp == bp) {
  686.                         /* and point it */
  687.                         wp->w_dotp = lp;
  688.                         wp->w_doto = 0;
  689.                         wp->w_flag |= WFHARD;
  690.                     }
  691.                     wp = wp->w_wndp;
  692.                 }
  693.                 /* in any case set the buffer . */
  694.                 bp->b_dotp = lp;
  695.                 bp->b_doto = 0;
  696.                 return(status);
  697.             }
  698.         }
  699.         lp = lp->l_fp;        /* on to the next line */
  700.     }
  701.         return(TRUE);
  702. }
  703.  
  704. execfile(f, n)    /* execute a series of commands in a file
  705. */
  706.  
  707. int f, n;    /* default flag and numeric arg to pass on to file */
  708.  
  709. {
  710.     register int status;    /* return status of name query */
  711.     char *fname[NSTRING];    /* name of file to execute */
  712.  
  713.     if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
  714.         return(status);
  715.  
  716.     /* otherwise, execute it */
  717.     while (n-- > 0)
  718.         if ((status=dofile(fname)) != TRUE)
  719.             return(status);
  720.  
  721.     return(TRUE);
  722. }
  723.  
  724. /*    dofile:    yank a file into a buffer and execute it
  725.         if there are no errors, delete the buffer on exit */
  726.  
  727. dofile(fname)
  728.  
  729. char *fname;    /* file name to execute */
  730.  
  731. {
  732.     register BUFFER *bp;    /* buffer to place file to exeute */
  733.     register BUFFER *cb;    /* temp to hold current buf while we read */
  734.     register int status;    /* results of various calls */
  735.     char bname[NBUFN];    /* name of buffer */
  736.  
  737.     makename(bname, fname);        /* derive the name of the buffer */
  738.     if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  739.         return(FALSE);
  740.  
  741.     bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  742.     cb = curbp;        /* save the old buffer */
  743.     curbp = bp;        /* make this one current */
  744.     /* and try to read in the file to execute */
  745.     if ((status = readin(fname, FALSE)) != TRUE) {
  746.         curbp = cb;    /* restore the current buffer */
  747.         return(status);
  748.     }
  749.  
  750.     /* go execute it! */
  751.     curbp = cb;        /* restore the current buffer */
  752.     if ((status = dobuf(bp)) != TRUE)
  753.         return(status);
  754.  
  755.     /* if not displayed, remove the now unneeded buffer and exit */
  756.     if (bp->b_nwnd == 0)
  757.         zotbuf(bp);
  758.     return(TRUE);
  759. }
  760.  
  761.  
  762. /* execute the startup file */
  763.  
  764. startup()
  765.  
  766. {
  767.     register int status;    /* status of I/O operations */
  768.     register int i;        /* index into help file names */
  769.     char fname[NSTRING];    /* buffer to construct file name in */
  770.  
  771. #if    (MSDOS & LATTICE) | V7
  772.     char *homedir;        /* pointer to your home directory */
  773.     char *getenv();
  774.     
  775.     /* get the HOME from the environment */
  776.     if ((homedir = getenv("HOME")) != NULL) {
  777.         /* build the file name */
  778.         strcpy(fname, homedir);
  779.         strcat(fname, "/");
  780.         strcat(fname, pathname[0]);
  781.  
  782.         /* and test it */
  783.         status = ffropen(fname);
  784.         if (status == FIOSUC) {
  785.             ffclose();
  786.             return(dofile(fname));
  787.         }
  788.     }
  789. #endif
  790.  
  791.     /* search through the list of startup files */
  792.     for (i=2; i < NPNAMES; i++) {
  793.         strcpy(fname, pathname[i]);
  794.         strcat(fname, pathname[0]);
  795.         status = ffropen(fname);
  796.         if (status == FIOSUC)
  797.             break;
  798.     }
  799.  
  800.     /* if it isn't around, don't sweat it */
  801.     if (status == FIOFNF)
  802.         return(TRUE);
  803.  
  804.     ffclose();    /* close the file to prepare for to read it in */
  805.  
  806.     return(dofile(fname));
  807. }
  808.  
  809.